<template>
  <el-dialog
    v-model="dialogVisible"
    width="450px"
    style="border-radius: 9px; border: 1px solid rgba(255, 255, 255, 0.5); padding: 0"
    :modal="false"
    :before-close="close"
    align-center
    @close="close"
  >
    <template #header>
      <div class="title">设备检测</div>
    </template>
    <template #default>
      <div v-if="step < 3" class="dialog-content">
        <!-- 步骤 -->
        <div class="tab">
          <div v-for="(item, index) in list" :key="index" class="tab-item">
            <img class="icon" :src="item.icon[item.status]" />
            <span>{{ item.label }}</span>
          </div>
        </div>
        <!-- 摄像头 -->
        <div v-if="step === 0" class="tab-container">
          <div class="video">
            <span v-if="!cameraType || !resolutionRatio" style="font-size: 24px; color: #999999">
              Video
            </span>
            <video
              v-else
              ref="videoElement"
              autoplay
              playsinline
              style="width: 100%; height: 100%"
            ></video>
          </div>
          <span class="m-t-16" style="align-self: center">您能看见摄像头画面吗？</span>
          <div class="form-item m-t-24">
            <span class="label">摄像头</span>
            <el-select v-model="cameraType" @change="initCamera">
              <el-option
                v-for="item in cameras"
                :key="item.id"
                :label="item.label"
                :value="item.id"
              />
            </el-select>
          </div>

          <div class="form-item m-t-16">
            <span class="label">分辨率</span>
            <el-select v-model="resolutionRatio" @change="initCamera">
              <el-option
                v-for="item in resolutionRatioList"
                :key="item.id"
                :label="item.label"
                :value="item.id"
              />
            </el-select>
          </div>
        </div>

        <!-- 麦克风 -->
        <div v-if="step === 1" class="tab-container" style="padding-bottom: 187px">
          <div class="voice">
            <span v-if="!microphoneType" style="font-size: 24px; color: #999999">Audio</span>
            <canvas v-else ref="waveformCanvas" class="voice"></canvas>
          </div>

          <div class="form-item m-t-24">
            <span class="label">麦克风</span>
            <el-select v-model="microphoneType" @change="startDetection">
              <el-option
                v-for="item in microphones"
                :key="item.id"
                :label="item.label"
                :value="item.id"
              />
            </el-select>
          </div>
          <span class="m-t-16" style="align-self: center">对着麦克风讲话，您能看到音量条吗？</span>
          <audio ref="audioElement" style="display: none"></audio>
        </div>

        <!-- 扬声器 -->
        <div v-if="step === 2" class="tab-container">
          <div class="form-item m-t-24">
            <span class="label">扬声器</span>
            <el-select v-model="loudspeakerType" @change="changeSpeaker">
              <el-option
                v-for="item in speakers"
                :key="item.id"
                :label="item.label"
                :value="item.id"
              />
            </el-select>
          </div>
          <div class="volume">
            <span>音量</span>
            <span>{{ volume }}%</span>
          </div>
          <div style="display: flex; align-items: center">
            <el-slider v-model="volume" :show-tooltip="false" @input="changeVolume" />
          </div>
          <img
            :src="isPlay ? playIcon : pauseIcon"
            class="m-t-40"
            style="width: 48px; height: 48px; align-self: center"
            @click="mp3Play"
          />
          <span class="m-t-16" style="align-self: center">点击播放声音</span>
          <span class="m-t-87" style="align-self: center">点击播放键，你能听见声音吗？</span>
        </div>
        <div class="footer-btn">
          <div class="btn white" @click="handleNext()">{{ step !== 2 ? "看不到" : "听不到" }}</div>

          <div class="btn blue" @click="handleNext('success')">
            {{ step !== 2 ? "能看见" : "能听见" }}
          </div>
        </div>
      </div>
      <div v-else class="dialog-content" style="border-top: 1px solid rgba(216, 216, 216, 0.5)">
        <div class="result-box">
          <img :src="resultIcon" />
          <span class="m-l-8 normal" :class="{ success: result, error: !result }">
            {{ resultText }}
          </span>
        </div>
        <div class="table-box">
          <!-- 表头 -->
          <div class="table-item">
            <div class="cell left">检测项目</div>
            <div class="line"></div>
            <div class="cell right">检测结果</div>
          </div>
          <!-- 表格数据 -->
          <div
            v-for="(item, index) in list"
            :key="index"
            class="table-item"
            :class="{ 'border-bottom': index === 0 || index === 1 }"
          >
            <div class="cell left">
              <img :src="item.pic" style="width: 20px; height: 20px" />
              <span class="m-l-8">{{ item.label }}</span>
            </div>
            <div class="line"></div>
            <div class="cell right">
              <div
                class="bg"
                :class="{
                  success: item.status === 2,
                  error: item.status !== 2,
                }"
              >
                <img
                  :src="item.status === 2 ? success : errorIcon"
                  style="width: 16px; height: 16px"
                />
                <span class="m-l-2">{{ item.status === 2 ? "正常" : "异常" }}</span>
              </div>
            </div>
          </div>
        </div>
        <!-- 结果按钮 -->
        <div
          class="result-btn"
          :class="{ 'success-btn': result, 'error-btn': !result }"
          @click="handleResultClick"
        >
          <span v-if="result">我知道了</span>
          <template v-else>
            <img
              src="@/assets/live/device/refresh.svg"
              style="width: 16px; height: 16px; margin-right: 8px"
            />
            <span>重新检测</span>
          </template>
        </div>
        <!-- 帮助与支持 -->
        <div class="help">
          <img src="@/assets/live/device/help.svg" style="width: 16px; height: 16px" />
          <span class="m-l-10">帮助与支持</span>
        </div>
      </div>
    </template>
  </el-dialog>
</template>
<script lang="ts">
export default {
  name: "DeviceCheck",
};
</script>
<script lang="ts" setup>
import { ref, watchEffect } from "vue";
import successIcon from "@/assets/live/device/success.svg";
import errorIcon from "@/assets/live/device/error.svg";
import cameraIng from "@/assets/live/device/camera_ing.svg";
import microphoneTodo from "@/assets/live/device/microphone_todo.svg";
import microphoneIng from "@/assets/live/device/microphone_ing.svg";
import loudspeakerTodo from "@/assets/live/device/loudspeaker_todo.svg";
import loudspeakerIng from "@/assets/live/device/loudspeaker_ing.svg";
import pauseIcon from "@/assets/live/device/pause.svg";
import playIcon from "@/assets/live/device/play.svg";
import success from "@/assets/live/device/success_green.svg";
import error from "@/assets/live/device/error_triangle.svg";
import cameraIcon from "@/assets/live/device/camera.svg";
import microphoneIcon from "@/assets/live/device/microphone.svg";
import loudspeakerIcon from "@/assets/live/device/loudspeaker.svg";
// 引入Agora RTC SDK
import AgoraRTC from "agora-rtc-sdk-ng";

const videoElement = ref(null);
let localVideoTrack: any = null;

interface Resolution {
  id: number;
  label: string;
  width: number;
  height: number;
}
const resolutionRatioList: Resolution[] = [
  {
    width: 854,
    height: 480,
    label: "480p",
    id: 1,
  },
];

// 选择摄像头，渲染画面到页面
const initCamera = async () => {
  if (!cameraType.value || !resolutionRatio.value) return;
  const tempObj = resolutionRatioList.find((item) => item.id === Number(resolutionRatio.value));
  let config;
  if (tempObj) {
    config = {
      width: tempObj.width, // 设置宽度
      height: tempObj.height, // 设置高度
    };
  }

  if (localVideoTrack) {
    localVideoTrack.stop();
    localVideoTrack = null;
  }

  try {
    localVideoTrack = await AgoraRTC.createCameraVideoTrack({
      cameraId: cameraType.value,
      encoderConfig: config,
    });

    // 确保 videoElement 已经挂载
    await nextTick();

    if (videoElement.value) {
      const playPromise = localVideoTrack.play(videoElement.value);
      if (playPromise !== undefined) {
        playPromise
          .then(() => {
            console.log("Playing video track");
          })
          .catch((error: string) => {
            console.error("Failed to play video track:", error);
          });
      } else {
        console.log("Playing video track");
      }
    }
  } catch (err) {
    console.error("Error:", err);
  }
};
const stopCamera = () => {
  if (localVideoTrack) {
    localVideoTrack.stop();
    localVideoTrack = null;
  }
};

const cameras = ref([]);
const microphones = ref([]);
const speakers = ref([]);

// 获取设备（摄像头、麦克风、扬声器）信息
async function getUserMediaDevices() {
  try {
    // 获取device列表
    const devices = await AgoraRTC.getDevices();
    cameras.value = devices
      .filter((device) => device.kind === "videoinput")
      .map((item) => {
        return { label: item.label, id: item.deviceId };
      });
    microphones.value = devices
      .filter((device) => device.kind === "audioinput")
      .map((item) => {
        return { label: item.label, id: item.deviceId };
      });
    speakers.value = devices
      .filter((device) => device.kind === "audiooutput")
      .map((item) => {
        return { label: item.label, id: item.deviceId };
      });

    console.log("Cameras:", cameras.value);
    console.log("Microphones:", microphones.value);
    console.log("Speakers:", speakers.value);
  } catch (error) {
    console.error("Error getting media devices:", error);
  }
}

const dialogVisible = ref(false);
// 初始化数据
const initStatus = () => {
  list.value = [
    {
      label: "摄像头",
      icon: ["", cameraIng, successIcon, errorIcon],
      value: 0,
      status: 1, // 0待检测 1检测中 2成功 3异常
      pic: cameraIcon,
    },
    {
      label: "麦克风",
      icon: [microphoneTodo, microphoneIng, successIcon, errorIcon],
      value: 1,
      status: 0,
      pic: microphoneIcon,
    },
    {
      label: "扬声器",
      icon: [loudspeakerTodo, loudspeakerIng, successIcon, errorIcon],
      value: 2,
      status: 0,
      pic: loudspeakerIcon,
    },
  ];
  cameraType.value = "";
  microphoneType.value = "";
  loudspeakerType.value = "";
};
// 显示
const show = (status: string) => {
  initStatus();
  dialogVisible.value = true;
  getUserMediaDevices();
};
// 关闭前的回调
const close = () => {
  dialogVisible.value = false;
  handleStop();
};

const step = ref(0); // 步骤 0摄像头 1麦克风 2扬声器
const list = ref([]);
const result = ref(false); // 检测结果
const resultIcon = ref(""); // 结果页面的标题图标
const resultText = ref(""); // 结果页面的按钮文案
watchEffect(() => {
  result.value = list.value.every((item) => item.status === 2);
  resultText.value = result.value ? "设备检测正常" : "设备检测异常";
  resultIcon.value = result.value ? success : error;
});
const waveformCanvas = ref(null);
const audioElement = ref(null);
let audioTrack;
let audioContext;
let analyser;
let dataArray;
let timer;

// 选择麦克风
const startDetection = async () => {
  try {
    if (!microphoneType.value) {
      console.error("请先选择一个麦克风设备");
      return;
    }

    // 创建音频轨道并指定设备ID
    audioTrack = await AgoraRTC.createMicrophoneAudioTrack({
      microphoneId: microphoneType.value,
    });

    // 获取 MediaStreamTrack
    const mediaStreamTrack = audioTrack.getMediaStreamTrack();

    // 确保 audioElement 的 srcObject 是正确的 MediaStream
    const mediaStream = new MediaStream([mediaStreamTrack]);
    audioElement.value.srcObject = mediaStream;

    // 获取音频上下文
    audioContext = new (window.AudioContext || window.webkitAudioContext)();
    const source = audioContext.createMediaStreamSource(mediaStream);
    analyser = audioContext.createAnalyser();
    analyser.fftSize = 2048;
    dataArray = new Uint8Array(analyser.frequencyBinCount);
    source.connect(analyser);
    drawWaveform();
  } catch (error) {
    console.error("启动检测失败:", error);
  }
};
const stopDetection = () => {
  if (timer) {
    clearInterval(timer);
    timer = null;
  }
  if (audioTrack) {
    audioTrack.close();
    audioTrack = null;
  }
  if (audioContext) {
    audioContext.close();
    audioContext = null;
  }
};
// 绘制声音波形图
const drawWaveform = () => {
  const canvas = waveformCanvas.value;
  const ctx = canvas.getContext("2d");

  // 样式配置参数
  const config = {
    barWidth: 2, // 条形基础宽度
    maxBarHeight: 200, // 最大条形高度
    gradientStart: "#3B82F6", // 渐变起始色
    gradientEnd: "#60A5FA", // 渐变结束色
    roundRadius: 2, // 条形圆角半径
    spacing: 1, // 条形间距
    smoothFactor: 0.2, // 高度平滑过渡系数
  };

  // 创建渐变
  const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
  gradient.addColorStop(0, config.gradientStart);
  gradient.addColorStop(1, config.gradientEnd);

  let lastHeights = new Array(dataArray.length).fill(0);

  timer = setInterval(() => {
    analyser.getByteTimeDomainData(dataArray);
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    const bufferLength = dataArray.length;
    const barTotalWidth = config.barWidth + config.spacing;
    const maxBars = Math.floor(canvas.width / barTotalWidth);

    // 平滑过渡处理
    for (let i = 0; i < maxBars; i++) {
      const value = (dataArray[i] - 128) / 128.0; // 转换为[-1,1]
      const targetHeight = Math.abs(value * config.maxBarHeight);
      lastHeights[i] =
        lastHeights[i] * (1 - config.smoothFactor) + targetHeight * config.smoothFactor;
    }

    // 绘制条形
    ctx.fillStyle = gradient;
    let x = 0;

    for (let i = 0; i < maxBars; i++) {
      const barHeight = lastHeights[i];
      const y = canvas.height / 2 - barHeight / 2;

      // 绘制圆角矩形
      ctx.beginPath();
      ctx.roundRect(x, y, config.barWidth, barHeight, [
        config.roundRadius,
        config.roundRadius,
        0,
        0,
      ]);
      ctx.fill();

      x += barTotalWidth;
    }
  }, 16); // ~60fps
};

const isPlay = ref(false);
// 选择扬声器
let speakerElement: HTMLAudioElement | null = null;
async function playSample() {
  if (!speakerElement) speakerElement = new Audio();
  speakerElement.src = "https://music.163.com/song/media/outer/url?type=2&id=317151.mp3";
  try {
    if ("setSinkId" in HTMLAudioElement.prototype) {
      await speakerElement.setSinkId(loudspeakerType.value);
    }
    await speakerElement.play();
    isPlay.value = true;
  } catch (err) {
    alert(`播放失败`);
  }
}
// 扬声器试音播放 按钮点击事件
const mp3Play = async () => {
  if (!loudspeakerType.value) {
    ElMessage.error("请选择扬声器");
    return;
  }
  if (speakerElement) {
    if (isPlay.value) {
      await speakerElement.pause();
      isPlay.value = false;
    } else {
      await speakerElement.play();
      isPlay.value = true;
    }
  } else {
    playSample();
  }
};
// 调整扬声器音量大小
function changeVolume() {
  speakerElement.volume = volume.value / 100; // volume属性只接受0到1之间的值
}
// 切换扬声器设备
async function changeSpeaker() {
  if (!("setSinkId" in HTMLAudioElement.prototype)) return;
  if (!speakerElement) return;
  try {
    await speakerElement.setSinkId(loudspeakerType.value);
  } catch (err) {
    console.error("切换扬声器失败:", err);
  }
}

const cameraType = ref(""); // 摄像头
const microphoneType = ref(""); // 麦克风
const loudspeakerType = ref(""); // 扬声器
const resolutionRatio = ref<number>(1); // 分辨率
const handleNext = (type: string = "") => {
  if (type === "success") {
    list.value[step.value] = { ...list.value[step.value], status: 2 };
  } else {
    list.value[step.value] = { ...list.value[step.value], status: 3 };
  }
  step.value++;
  handleStop(); // 关闭视频或音频流
  if (step.value === 3) return;
  list.value[step.value] = { ...list.value[step.value], status: 1 };
};
const volume = ref(50);

const handleResultClick = () => {
  if (result.value) {
    close(); // 我知道了
  } else {
    step.value = 0; // 重新检测
    initStatus();
  }
};
const handleStop = () => {
  stopCamera();
  stopDetection();
  if (speakerElement) {
    speakerElement.pause();
    speakerElement.src = "";
    speakerElement = null;
  }
};
onBeforeUnmount(() => {
  handleStop();
});

defineExpose({ show, close });
</script>
<style lang="scss" scoped>
.title {
  padding: 15px 32px 0px;
  font-size: 16px;
  font-weight: bold;
  text-align: center;
  transform: translateX(8%);
}
.dialog-content {
  color: #000;

  .tab {
    border-top: 1px solid rgba(216, 216, 216, 0.5);
    border-bottom: 1px solid rgba(216, 216, 216, 0.5);
    display: flex;
    justify-content: space-between;
    padding: 24px 63px;
    .tab-item {
      display: flex;
      flex-direction: column;
      align-items: center;
      .icon {
        width: 40px;
        height: 40px;
        margin-bottom: 8px;
        color: #6b7280;
      }
    }
  }
  .tab-container {
    padding: 24px;
    padding-bottom: 48px;
    display: flex;
    flex-direction: column;
    .video {
      width: 402px;
      height: 225px;
      background: #f3f4f6;
      border-radius: 12px;
      overflow: hidden;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .voice {
      width: 386px;
      height: 100px;
      border-radius: 4px;
      background-color: #f3f4f6;
      margin: 0 8px;
      overflow: hidden;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .form-item {
      display: flex;
      align-items: center;
      .label {
        min-width: 42px;
        flex: 1;
        color: #4b5563;
        margin-right: 38px;
      }
    }
    .volume {
      margin-top: 40px;
      margin-bottom: 13px;
      display: flex;
      justify-content: space-between;
    }
  }

  .footer-btn {
    margin: 0 18px;
    padding: 24px 31px;
    display: flex;
    justify-content: space-between;
    border-top: 1px solid rgba(216, 216, 216, 0.5);
    .btn {
      font-size: 16px;
      padding: 11px 50px;
      border-radius: 4px;
      cursor: default;
    }
    .blue {
      background-color: #3c80ff;
      color: #fff;
    }
    .white {
      background-color: #fff;
      color: #374151;
      border: 1px solid #d1d5db;
    }
  }
  .result-box {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 49px 0 35px;
    .normal {
      font-size: 20px;
    }
    .error {
      color: #ff4d4f;
    }
    .success {
      color: #52c41a;
    }
  }
  .table-box {
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    overflow: hidden;
    margin: 0 25px 32px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 16px;

    .table-item {
      display: flex;

      .cell {
        padding: 16px;
        box-sizing: border-box;
        flex: 1;
        display: flex;
        align-items: center;
      }
      .line {
        width: 1px;
        height: 56px;
        background-color: #e5e7eb;
      }
      .left {
        // background-color: pink;
        // border-right: 1px solid #e5e7eb;
      }
      .right {
        // background-color: lightblue;
        font-size: 14px;
        .bg {
          padding: 4px 12px;
          border-radius: 14px;
          display: flex;
          align-items: center;
        }
        .success {
          color: #52c41a;
          background: #f0fdf4;
        }
        .error {
          color: #ff4d4f;
          background: #fef2f2;
        }
      }
    }
    .table-item:first-child {
      background: #f9fafb;
      color: #4b5563;
    }
    .border-bottom {
      border-bottom: 1px solid #e5e7eb;
    }
  }
  .result-btn {
    padding: 8px;
    font-size: 16px;
    color: #fff;
    margin: 0 24px;
    border-radius: 4px;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: default;
  }
  .success-btn {
    background-color: #52c41a;
  }
  .error-btn {
    background-color: #ff4d4f;
  }
  .help {
    padding-bottom: 24px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 14px;
    color: #4b5563;
  }
}
</style>
